﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
using System.Media;
using System.Drawing;
using System.Threading;

namespace PacMan
{
    class GameProcess
    {
        private RectangleF[] _maze;
        private Pacman pacman;
        private Blinky blinky;
        private Inky inky;
        private Pinky pinky;
        private Clyde clyde;
        private RectangleF[] pacDots;
        private Bonus bonus;
        private Point _captionCoordinates = new Point();
        private System.Timers.Timer _bonusTimer;
        private System.Timers.Timer _bonusExistsTime;
        private System.Timers.Timer _pointsTimer;
        private System.Timers.Timer _levelNotice;
        private int _pacDotsAmount = 200;
        private CharactersDrawer _charactersDrawer = new CharactersDrawer();
        private bool _initialization = true;
        private int _currentLevel = 1;
        private SoundManager _soundManager = new SoundManager();
        private LeaderboardManager _leaderBoardManager = new LeaderboardManager();
        private bool isAddedToLeaderBoard = false;

        public GameProcess()
        {
            _bonusTimer = new System.Timers.Timer(25000);
            _bonusExistsTime = new System.Timers.Timer(7000);
            _pointsTimer = new System.Timers.Timer(3000);
            _levelNotice = new System.Timers.Timer(4000);
            _maze = Environment.GenerateMaze();
            pacman = new Pacman(312, 470, 7);
            
            inky = new Inky(-100, -100, 0);
            blinky = new Blinky(-100, -100, 0);
            pinky = new Pinky(-100, -100, 0);
            clyde = new Clyde(-100, -100, 0);
                        
            bonus = new Bonus();
            pacDots = Environment.CreatePacDots(_pacDotsAmount, _maze);
            _bonusExistsTime.Elapsed += bonusExistsTime_Elapsed;
            _bonusTimer.Elapsed += _bonusTimer_Elapsed;
            _bonusTimer.Start();
            _levelNotice.Elapsed += levelNotice_Elapsed;
            _pointsTimer.Elapsed += pointsTimer_Elapsed;
            _soundManager.AddToPlaylist(Environment.GetFullFileName("Sound\\pacman_beginning.wav"));
        }

        private void _bonusTimer_Elapsed(object sender, EventArgs e) 
        {
            bonus.BonusChoosing(_maze);
            _bonusTimer.Start();
            _bonusExistsTime.Start();
        }
        
        private void DefaultPositions() 
        {
            pacman.X = 312; pacman.Y = 470;

            blinky.X = 150; blinky.Y = 100; 
            inky.X = 470; inky.Y = 100;
            pinky.X = 150; pinky.Y = 100;
            clyde.X = 325; clyde.Y = 100;

            inky.Position = Position.Down;
            pinky.Position = Position.Down;
        }

        private void _IncreaseGhostsSpeed(int value)
        {
            blinky.Speed += value;
            inky.Speed += value;
            pinky.Speed += value;
        }
        
        private void Level1(PaintEventArgs e) 
        {
            
            if (_initialization == true)
            {
                _levelNotice.Enabled = true;
                _levelNotice.Start();
                DefaultPositions();
                blinky.Speed = 3;
                inky.Speed = 5;
                pinky.Speed = 5;
                clyde.Speed = 1;
                _initialization = false;
            }

            if (_levelNotice.Enabled == true) 
            {
                e.Graphics.DrawString("Level " + _currentLevel, new Font("Quartz MS", 100), Brushes.White, 75, 200);
            }
            
            if (_pacDotsAmount == 0) 
            {
                _initialization = true;
                _currentLevel++;
                pacman.HP++;
              
            }
        }
     
        private void Level2(PaintEventArgs e)
        {
            if (_initialization == true)
            {
                _levelNotice.Enabled = true;
                _levelNotice.Start();
                DefaultPositions();
                _IncreaseGhostsSpeed(1);
                _pacDotsAmount = 200;
                pacDots = Environment.CreatePacDots(_pacDotsAmount, _maze);
                _initialization = false;
            }

            if (_levelNotice.Enabled == true)
            {
                e.Graphics.DrawString("Level " + _currentLevel, new Font("Quartz MS", 100), Brushes.White, 75, 200);
            }

            if (_pacDotsAmount == 0)
            {
                _initialization = true;
                _currentLevel++;
                pacman.HP++;
            }
        }

        private void Level3(PaintEventArgs e)
        {
            if (_initialization == true)
            {
                _levelNotice.Enabled = true;
                _levelNotice.Start();

                DefaultPositions();
                _IncreaseGhostsSpeed(1);
                _pacDotsAmount = 200;
                pacDots = Environment.CreatePacDots(_pacDotsAmount, _maze);
                _initialization = false;
            }

            if (_levelNotice.Enabled == true)
            {
                e.Graphics.DrawString("Level " + _currentLevel, new Font("Quartz MS", 100), Brushes.White, 75, 200);
            }

            if (_pacDotsAmount == 0)
            {
                _initialization = true;
                _currentLevel++;
                pacman.HP++;
            }
        }

        private void Level4(PaintEventArgs e)
        {
            if (_initialization == true)
            {
                _levelNotice.Enabled = true;
                _levelNotice.Start();
                _IncreaseGhostsSpeed(1);
                DefaultPositions();
                _pacDotsAmount = 200;
                pacDots = Environment.CreatePacDots(_pacDotsAmount, _maze);
                _initialization = false;
            }

            if (_levelNotice.Enabled == true)
            {
                e.Graphics.DrawString("Level " + _currentLevel, new Font("Quartz MS", 100), Brushes.White, 75, 200);
            }

            if (_pacDotsAmount == 0)
            {
                _initialization = true;
                _currentLevel++;
                pacman.HP++;
            }
        }

        private void Level5(PaintEventArgs e)
        {
            if (_initialization == true)
            {
                _levelNotice.Enabled = true;
                _levelNotice.Start();
                _IncreaseGhostsSpeed(1);
                DefaultPositions();
                _pacDotsAmount = 200;
                pacDots = Environment.CreatePacDots(_pacDotsAmount, _maze);
                _initialization = false;
            }

            if (_levelNotice.Enabled == true)
            {
                e.Graphics.DrawString("Level " + _currentLevel, new Font("Quartz MS", 100), Brushes.White, 75, 200);
            }

            if (_pacDotsAmount == 0)
            {
                _initialization = true;
                _currentLevel++;
                pacman.HP++;
            }
        }

        private void Level6(PaintEventArgs e)
        {
            if (_initialization == true)
            {
                _levelNotice.Enabled = true;
                _levelNotice.Start();
                _IncreaseGhostsSpeed(1);
                DefaultPositions();
                _pacDotsAmount = 200;
                pacDots = Environment.CreatePacDots(_pacDotsAmount, _maze);
                _initialization = false;
            }

            if (_levelNotice.Enabled == true)
            {
                e.Graphics.DrawString("Level " + _currentLevel, new Font("Quartz MS", 100), Brushes.White, 75, 200);
            }

            if (_pacDotsAmount == 0)
            {
                _initialization = true;
                _currentLevel++;
                pacman.HP++;
            }
        }
        
        /// <summary>
        /// Starts the game and contains all the game process logic
        /// </summary>
        /// <param name="e">Used to draw on the main game form</param>
        public void StartGame(PaintEventArgs e) 
        {

            _soundManager.Play();
            DrawEnvironment(e);
            DrawCharacters(e);
            PacmanBehaviour(e);

            switch (_currentLevel) 
            {
                case 1:
                    {
                        Level1(e);
                        break;
                    }
                case 2: 
                    {
                        Level2(e);
                        break;
                    }
                case 3:
                    {
                        Level3(e);
                        break;
                    }
                case 4:
                    {
                        Level4(e);
                        break;
                    }
                case 5: 
                    {
                        Level5(e);
                        break;
                    }
                case 6: 
                    {
                        Level6(e);
                        break;
                    }
                case 7: 
                    {
                        pacman.Speed = 0;
                        DefaultPositions();
                        blinky.Speed = 0;
                        inky.Speed = 0;
                        pinky.Speed = 0;
                        clyde.Speed = 0;
                        e.Graphics.DrawString("Congratulations!", new Font("Quartz MS", 50), Brushes.White, 20, 200);
                        e.Graphics.DrawString("You win!", new Font("Quartz MS", 50), Brushes.White, 200, 260);
                        e.Graphics.DrawString("Your score: " + pacman.Points, new Font("Quartz MS", 50), Brushes.White, 100, 380);
                        break;
                    }
            }
            
            if (pacman.IsAlive == false) 
            {
                if (pacman.HP > 0)
                {
                    pacman.IsAlive = true;
                    pacman.X = 312; pacman.Y = 470;
                    DefaultPositions();
                }
                else 
                {
                    e.Graphics.DrawString("The end", new Font("Quartz MS", 100), Brushes.White, 75, 200);
                    e.Graphics.DrawString("Your score: "+pacman.Points, new Font("Quartz MS", 50), Brushes.White, 100, 380);
                    pacman.Speed = 0;
                    DefaultPositions();
                    blinky.Speed = 0;
                    inky.Speed = 0;
                    pinky.Speed = 0;
                    clyde.Speed = 0;
                    if (isAddedToLeaderBoard == false)
                    {
                        _leaderBoardManager.AddPlayerToFile(Environment.PlayerName, pacman.Points);
                        isAddedToLeaderBoard = true;
                    }
                }
            }
        }

        /// <summary>
        /// Draws all the characters
        /// </summary>
        /// <param name="e">Used to draw on the main game form</param>
        
        private void DrawCharacters(PaintEventArgs e) 
        {
            _charactersDrawer.DrawPacman(pacman, e);
            _charactersDrawer.DrawInky(inky, e);
            _charactersDrawer.DrawPinky(pinky, e);
            _charactersDrawer.DrawClyde(clyde, e);
            _charactersDrawer.DrawBonus(bonus, e);
            _charactersDrawer.DrawBlinky(blinky, e);
        }
        /// <summary>
        /// Draw all the environments items, such as main maze, pacman HP, collected points, pac dots etc.
        /// </summary>
        /// <param name="e">Used to draw on the main game form</param>
        private int GetTopScore() 
        {
            var topPlayer = _leaderBoardManager.GetTopPlayer();
            if (topPlayer > pacman.Points)
            {
                return topPlayer;
            }
            else 
            {
                return pacman.Points;
            }

        }
        
        private void DrawEnvironment(PaintEventArgs e) 
        {
            e.Graphics.FillRectangle(Brushes.Black, Environment.MinX, Environment.MinY, Environment.MaxX, Environment.MaxY);
            e.Graphics.DrawRectangle(Pens.White, Environment.MaxX, Environment.MinY, 145, Environment.MaxY);
            e.Graphics.FillRectangle(Brushes.DarkBlue, Environment.MaxX, Environment.MinY, 150, Environment.MaxY);
            e.Graphics.DrawString("Score:\n", new Font("Quartz MS", 16), Brushes.White, 680, 30);
            e.Graphics.DrawString("" + pacman.Points, new Font("Quartz MS", 14), Brushes.White, 700, 60);
            e.Graphics.DrawString("Top Score:\n", new Font("Quartz MS", 16), Brushes.White, 660, 90);
            e.Graphics.DrawString("" + GetTopScore(), new Font("Quartz MS", 14), Brushes.White, 680, 120);
            e.Graphics.DrawString("Press 'P' to pause.", new Font("Quartz MS", 10), Brushes.White, 658, 500);
            e.Graphics.DrawString("Press 'Esc' to exit.", new Font("Quartz MS", 10), Brushes.White, 658, 520);
            int y = 220;
            e.Graphics.DrawString("HP:\n", new Font("Quartz MS", 16), Brushes.White, 700, 190);
            for (int i = 0; i < pacman.HP; i++)
            {
                e.Graphics.DrawImage(new Bitmap("Images\\HP.png"), 710, y);
                y += 30;
            }
            e.Graphics.FillRectangles(Brushes.DarkBlue, _maze);
            e.Graphics.FillRectangles(Brushes.Gold, pacDots);
        }

        private void levelNotice_Elapsed(object sender, ElapsedEventArgs e)
        {
            _levelNotice.Stop();
        }
        
        private void pointsTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _pointsTimer.Stop();
        }
        
        private void bonusExistsTime_Elapsed(object sender, ElapsedEventArgs e)
        {
            bonus.X = -100;
            bonus.Y = -100;
            _bonusExistsTime.Stop();
        }

        public void MovePacman(KeyEventArgs e) 
        {
            pacman.WhereToMove(e);
        }
        /// <summary>
        /// This method defines standart pacman behaviour on the game map
        /// </summary>
        private void PacmanBehaviour(PaintEventArgs e) 
        {
            //Pacman behaviour when intersects with obstacles
            pacman.IntersectsWithObstacle(_maze);

            //Pacman behaviour when he finds bonus
            if (pacman.IntersectsWithGameObj(bonus))
            {
                _pointsTimer.Enabled = true;
                _pointsTimer.Start();
                _captionCoordinates.X = bonus.X;
                _captionCoordinates.Y = bonus.Y;
                bonus.X = -100;
                bonus.Y = -100;
                _soundManager.AddToPlaylist(Environment.GetFullFileName(@"Sound\\pacman_eatfruit.wav"));

            }

            if (_pointsTimer.Enabled == true)
            {
                e.Graphics.DrawString("+" + bonus.Points, new Font("Quartz MS", 16), Brushes.White, _captionCoordinates.X, _captionCoordinates.Y);
            }




            
            for (int i = 0; i < pacDots.Length; i++)
            {
                if (pacman.CollectPacDot(pacDots[i]) == true)
                {
                    pacDots[i].Y = -100;
                    pacDots[i].X = -100;
                    _pacDotsAmount--;                    
                }
            }

            if (pacman.IntersectsWithGameObj(blinky) || pacman.IntersectsWithGameObj(pinky) || pacman.IntersectsWithGameObj(inky)
                || pacman.IntersectsWithGameObj(clyde))
            {
                _soundManager.AddToPlaylist(Environment.GetFullFileName(@"Sound\\pacman_death.wav"));
            }
        
        }
        
        /// <summary>
        /// This method enables to move all the characters through maze
        /// </summary>
        public void MoveObjects() 
        {
            pacman.Move();
            blinky.Move();
            inky.Move(_maze);
            pinky.Move(_maze);
            //clyde.Move(obstacles);
            clyde.Chase(pacman);
        }
    
    }
}
